package com.daffodil.workable.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.daffodil.core.util.HqlUtils;
import com.daffodil.core.dao.JpaDao;
import com.daffodil.core.entity.Query;
import com.daffodil.framework.exception.BaseException;
import com.daffodil.workable.constant.WorkableConstant;
import com.daffodil.workable.entity.WorkableForm;
import com.daffodil.workable.entity.WorkableLine;
import com.daffodil.workable.entity.WorkableNode;
import com.daffodil.workable.entity.WorkableTask;
import com.daffodil.workable.entity.WorkableTask.Version;
import com.daffodil.workable.service.IWorkableTaskService;
import com.daffodil.workable.util.WorkableUtils;
import com.daffodil.util.StringUtils;

/**
 * -计划任务Service接口业务实现层
 * @author yweijian
 * @date 2022-04-06
 * @version 1.0
 * @description
 */
@Service
public class WorkableTaskServiceImpl implements IWorkableTaskService {

    @Autowired
    private JpaDao<String> jpaDao;

    @Override
    public List<WorkableTask> selectWorkableTaskList(Query<WorkableTask> query) {
        StringBuffer hql = new StringBuffer("from WorkableTask where 1=1 ");
        List<Object> paras = new ArrayList<Object>();
        HqlUtils.createHql(hql, paras, query);
        return jpaDao.search(hql.toString(), paras, WorkableTask.class, query.getPage());
    }

    @Override
    public WorkableTask selectWorkableTaskById(String id) {
        return jpaDao.find(WorkableTask.class, id);
    }

    @Override
    @Transactional
    public void insertWorkableTask(WorkableTask workableTask) {
        workableTask.setStatus(WorkableConstant.WORKABLE_WRITEABLE);
        workableTask.setTaskVersion(new Version(0, 0, 0, 0));
        jpaDao.save(workableTask);
    }

    @Override
    @Transactional
    public void updateWorkableTask(WorkableTask workableTask) {
        WorkableTask task = jpaDao.find(WorkableTask.class, workableTask.getId());
        if(task.getStatus().equals(WorkableConstant.WORKABLE_READONLY)) {
            throw new BaseException(50001);
        }
        jpaDao.update(workableTask);
    }

    @Override
    @Transactional
    public void deleteWorkableTaskByIds(String[] ids) {
        jpaDao.delete(WorkableTask.class, ids);
    }

    @Override
    @Transactional
    public void deployWorkableTaskByIds(String[] ids, Version version) {
        if(StringUtils.isEmpty(ids)) {
            return;
        }
        for(String taskId : ids) {
            WorkableTask task = jpaDao.find(WorkableTask.class, taskId);
            
            if(StringUtils.isNull(task) || !WorkableConstant.WORKABLE_WRITEABLE.equals(task.getStatus())) {
                throw new BaseException(50002);
            }
            
            List<Object> paras = new ArrayList<Object>();
            paras.add(version.getMajor());
            paras.add(version.getMinor());
            paras.add(version.getPatch());
            paras.add(version.getBuild());
            paras.add(taskId);
            int count = jpaDao.count("from WorkableTask where major = ? and minor = ? and patch = ? and build = ? and deployId = ?", paras);
            if(count > 0) {
                throw new BaseException(50003);
            }
            
            WorkableTask target = new WorkableTask();
            BeanUtils.copyProperties(task, target, "id");
            target.setStatus(WorkableConstant.WORKABLE_READONLY);
            target.setDeployTime(new Date());
            target.setDeployId(taskId);
            target.setTaskVersion(version);
            jpaDao.save(target);
            
            this.deployWorkableNode(taskId, target.getId());
            this.deployWorkableLine(taskId, target.getId());
            this.deployWorkableForm(taskId, target.getId());
        }
    }
    
    /**
     * 部署WorkableNode
     * @param taskId
     * @param targetId
     */
    private void deployWorkableNode(String taskId, String targetId) {
        List<WorkableNode> nodes = jpaDao.search("from WorkableNode where taskId = ?", taskId, WorkableNode.class);
        if(StringUtils.isNotEmpty(nodes)) {
            nodes.stream().forEach(node -> {
                WorkableNode target = new WorkableNode();
                BeanUtils.copyProperties(node, target, "id");
                target.setTaskId(targetId);
                jpaDao.save(target);
            });
        }
    }
    
    /**
     * 部署WorkableLine
     * @param taskId
     * @param targetId
     */
    private void deployWorkableLine(String taskId, String targetId) {
        List<WorkableLine> lines = jpaDao.search("from WorkableLine where taskId = ?", taskId, WorkableLine.class);
        if(StringUtils.isNotEmpty(lines)) {
            lines.stream().forEach(line -> {
                WorkableLine target = new WorkableLine();
                BeanUtils.copyProperties(line, target, "id");
                target.setTaskId(targetId);
                jpaDao.save(target);
            });
        }
    }
    
    /**
     * 部署WorkableForm
     * @param taskId
     * @param targetId
     */
    private void deployWorkableForm(String taskId, String targetId) {
        List<WorkableForm> forms = jpaDao.search("from WorkableForm where taskId = ?", taskId, WorkableForm.class);
        if(StringUtils.isNotEmpty(forms)) {
            forms.stream().forEach(form -> {
                WorkableForm target = new WorkableForm();
                BeanUtils.copyProperties(form, target, "id");
                target.setTaskId(targetId);
                jpaDao.save(target);
            });
        }
    }
    
    @Override
    @Transactional
    public void runWorkableTaskByIds(String[] ids, String runmode) {
        if(StringUtils.isEmpty(ids) || StringUtils.isEmpty(runmode)) {
            return;
        }
        for(String taskId : ids) {
            WorkableNode workableNode = jpaDao.find("from WorkableNode where modelId = 'start-node' and type = 'start' and taskId = ?", taskId, WorkableNode.class);
            WorkableUtils.run(workableNode, runmode);
        }
    }

    @Override
    @Transactional
    public void trashWorkableTaskByIds(String[] ids) {
        if(StringUtils.isEmpty(ids)) {
            return;
        }
        for(String taskId : ids) {
            WorkableTask task = jpaDao.find(WorkableTask.class, taskId);
            if(StringUtils.isNull(task) || !WorkableConstant.WORKABLE_READONLY.equals(task.getStatus())) {
                throw new BaseException(50004);
            }
            int count = jpaDao.count("from WorkablePlan where taskId = ?", taskId);
            if(count > 0) {
                throw new BaseException(50005);
            }
            task.setStatus(WorkableConstant.WORKABLE_TRASHABLE);
            jpaDao.update(task);
        }
    }

}
